﻿#include "Containers.h"
#include "../PublicService/SettingData.h"

using namespace BusinessLayer;
using namespace DeviceLayer;

ContainerForDevice ContainerForDevice::instance; //static member builder

ContainerForDevice::ContainerForDevice()
{
    dataPool = std::make_shared<DataPool>();
}

ContainerForDevice::~ContainerForDevice()
{
    //退出query线程
    run = false;
    if (queryDataThread.joinable())
        queryDataThread.join();
}

bool ContainerForDevice::CreateFromSettingData()
{
    QString path = "Devices/Device[%1]";
    bool result = CreateObjectsFromSettingData<Device>(path);
    if (result)
    {
        for (size_t i = 0; i < size(); i++)
        {
            //给Device对象设置dataPool
            operator[](static_cast<int>(i))->SetDataPoolObj(dataPool);

            //是否需要主动定时调用QueryData方法进行数据采集
            operator[](static_cast<int>(i))->autoQuerySetup.autoQueryTimeSpan = SettingData::instance.GetDataInt(path.arg(i) + "::autoQueryTimeSpan", 0);
            operator[](static_cast<int>(i))->autoQuerySetup.independentQueryTask = SettingData::instance.GetDataInt(path.arg(i) + "::indepentQueryTask", 0);
        }
        return true;
    }
    else
        return false;
}

void ContainerForDevice::StartQueryDataThread()
{
    run = true;
    queryDataThread = std::thread(&ContainerForDevice::QueryData, this);
}

void ContainerForDevice::QueryData()
{
    while (run)
    {
        for (size_t i = 0; i < size(); i++)
        {
            if (operator[](static_cast<int>(i))->autoQuerySetup.autoQueryTimeSpan != 0)  //如果这个设备对象需要系统自动按时调用QueryData
            {
                auto now = std::chrono::steady_clock::now();
                if (std::chrono::duration_cast<std::chrono::milliseconds>(now - operator[](static_cast<int>(i))->autoQuerySetup.lastCallTime).count() >= operator[](static_cast<int>(i))->autoQuerySetup.autoQueryTimeSpan)
                {
                    //这里的计时并不一定准确。由于每个设备对象QueryData的执行时间不同，有可能上一个设备占用了太多时间，会造成下一个设备超过
                    //应该调用QueryData的时间。这个情况不处理。
                    //程序员应该在写设备的QueryData函数时注意这个问题，QueryData应立即返回，不应造成阻塞。
                    operator[](static_cast<int>(i))->autoQuerySetup.lastCallTime = now;  //保存上次本设备调用QueryData的时间。
                    if (!operator[](static_cast<int>(i))->QueryData())
                    {
                        LOGERR("ContainerForDevice::QueryData", "设备：" + objects[i]->GetName() + " 执行QueryData返回false。");
                    }
                }
            }
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(20)); //Do not consume all cpu time.
    }
}
